package designpattern

import (
	"fmt"
	"strconv"
	"strings"
)

var mockChooseMap = map[string]int{"Lisa": 12, "Nick": 33, "Martin": 143, "Benjamin": 2, "John": 7}

type Command interface {
	exec(command string) string
}

type LsCommand struct {
}

type SelectCommand struct {
}

type UpdateCommand struct {
}

type ChooseCommand struct {
}

func (ls *LsCommand) exec(command string) string {
	fmt.Printf("exec command: %s\n", command)
	keys := make([]string, 0, len(mockChooseMap))
	for k := range mockChooseMap {
		keys = append(keys, k)
	}
	return strings.Join(keys, ",")
}

func (choose *ChooseCommand) exec(command string) string {
	fmt.Printf("exec command: %s\n", command)
	strarray := strings.Fields(strings.TrimSpace(command))
	return strarray[1]
}

func (selectCmd *SelectCommand) exec(command string) string {
	fmt.Printf("exec command: %s\n", command)
	strarray := strings.Fields(strings.TrimSpace(command))
	return fmt.Sprintf("%s %d", strarray[1], mockChooseMap[strarray[1]])
}

func (update *UpdateCommand) exec(command string) string {
	fmt.Printf("exec command: %s\n", command)
	strarray := strings.Fields(strings.TrimSpace(command))

	v, _ := strconv.ParseInt(strarray[1], 0, 64)
	mockChooseMap[strarray[2]] = int(v)

	return fmt.Sprintf("update %s successfully!", strarray[2])
}

func CommandInvoker(command string) string {
	commands := strings.Split(command, "|")

	prevExecResult := ""
	for _, v := range commands {
		currCmd := fmt.Sprintf("%s %s", strings.Trim(v, " "), prevExecResult)
		result := ""
		if strings.Contains(v, "ls") {
			cmd := &LsCommand{}
			result = cmd.exec(currCmd)
		} else if strings.Contains(v, "select") {
			cmd := &SelectCommand{}
			result = cmd.exec(currCmd)
		} else if strings.Contains(v, "choose") {
			cmd := &ChooseCommand{}
			result = cmd.exec(currCmd)
		} else if strings.Contains(v, "update") {
			cmd := &UpdateCommand{}
			result = cmd.exec(currCmd)
		}

		fmt.Println(result)
		prevExecResult = result
	}

	return prevExecResult
}
